#include <stdio.h>
#include <string.h>
#include <sys/select.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>

#include "select_event.h"
#include "pub_type.h"
#include "pub_log.h"

#define SOCKET int
#define LISTEN_MAX  (1024)
#define MAX_LINK_NUM_INT (20)
sw_fd_set_t     fd_set_s;

sw_int_t handler_work(void *buf)
{
    slog_info("data = [%s]", (char *)buf);
}

sw_int_t lsn_accept(void *sock)
{
    sw_fd_list_t    fd_list;
    SOCKET accept_id = -1;
    int ret = -1;

    memset(&fd_list, 0x00, sizeof(sw_fd_list_t));

    accept_id = accept(*(SOCKET *)sock, NULL, NULL);
    if(accept_id < 0)
    {
        slog_info("accept err! (error code: %d - %s)", errno, strerror(errno));
        return -1;
    }

    fd_list.fd = accept_id;
    fd_list.data = NULL;
    fd_list.event_handler = (sw_event_handler_pt)handler_work;
    ret = select_add_event(&fd_set_s, &fd_list);
    if (ret != SW_OK)
    {
        slog_info("[%s][%d] select_add_event error!", __FILE__, __LINE__);
        return SW_ERROR;
    }
}


int main(int argc, char **argv)
{
    int fd = 0;
    int ret = -1;
    int retval = -1;
    int server_sockfd = -1;
    int maxfd = -1;
    SOCKET linsten_sock[LISTEN_MAX];
    int cli_len;
    int port ;
    fd_set rfds;
    struct timeval timeout;
    struct sockaddr_in cli_addr;



    memset(&timeout, 0x00, sizeof(timeout));
    memset(linsten_sock, -1, sizeof(linsten_sock) );

    ret = WrLog_init_by_logname_logpath("server", "./");
    if(ret < 0)
    {
        fprintf(stderr, "WrLog_init err!\n");
        WrLog_release();
        return -1;
    }
    if(argc < 2)
    {
        slog_info("Usage:\n");
        slog_info("server <port>\n");
        WrLog_release();
        return -1;
    }
    port = atoi(argv[1]);
    ret = server_init(&server_sockfd, port);
    if(ret < 0)
    {
        slog_info("server_init err!\n");
        WrLog_release();
        return -1;
    }
    ret = lsn_main(server_sockfd);
    if (ret != SW_OK)
    {
        slog_info("[%s][%d] lsn_cycle_run error!", __FILE__, __LINE__);
        WrLog_release();
        return SW_ERROR;
    }
    slog_info("[%s][%d] lsn_cycle_run success!", __FILE__, __LINE__);

    WrLog_release();
    return 0;
}
int server_init( SOCKET *server_sockfd, const int port_int )
{
    struct sockaddr_in server_addr;
    int val = 1;

    // socket
    if( (*server_sockfd = socket( AF_INET, SOCK_STREAM, 0 )) == -1 )
    {
        slog_info( "Error: create socket! (error code: %d - %s)\n", errno, strerror(errno) );
        return -1;
    }

    // addr
    setsockopt(*server_sockfd, SOL_SOCKET, SO_REUSEADDR, (char *) &val, sizeof (val));
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons( port_int );
    server_addr.sin_addr.s_addr = INADDR_ANY;
    bzero( &(server_addr.sin_zero), 8 );

    // bind
    if( bind( *server_sockfd, (struct sockaddr *)&server_addr, sizeof(struct sockaddr)) == -1 )
    {
        slog_info( "Error: bind! (error code: %d - %s)\n", errno, strerror(errno) );
        return -1;
    }

    // listen
    if( listen( *server_sockfd, MAX_LINK_NUM_INT ) == -1 )
    {
        slog_info("Error: listen! (error code:%d - %s)\n", errno, strerror(errno) );
        return -1;
    }

    return 0;
}
int lsn_main(SOCKET server_sockfd)
{
    int	ret = 0;
    int	recv_cnt = 0;
    sw_int32_t	i = 0;
    sw_fd_list_t	*fd_work;
    sw_fd_list_t    fd_list;
    sw_int64_t	timer = 0;
    char msg_len_buf[5];
    long msg_len = -1;
    //for time
    struct  timeval  start;
    struct  timeval  end;
    unsigned long rtimer;


    memset(&fd_set_s, 0x00, sizeof(sw_fd_set_t));
    memset(&fd_list, 0x00, sizeof(sw_fd_list_t));
    memset(msg_len_buf, 0x00, sizeof(msg_len_buf));

    ret = select_init(&fd_set_s);
    if (ret != SW_OK)
    {
        slog_info("[%s][%d] select_init error!", __FILE__, __LINE__);
        return SW_ERROR;
    }

    fd_list.fd = server_sockfd;
    fd_list.data = &server_sockfd;
    fd_list.event_handler = (sw_event_handler_pt)lsn_accept;
    ret = select_add_event(&fd_set_s, &fd_list);
    if (ret != SW_OK)
    {
        slog_info("[%s][%d] select_add_event error!", __FILE__, __LINE__);
        return SW_ERROR;
    }

    while (1)
    {
        slog_info("begin select\n");
        slog_fflush();
        timer = 10000;
        recv_cnt = select_process_events(&fd_set_s, &fd_work, timer);
        if (recv_cnt < 0)
        {
            slog_info("[%s][%d] select_process_events error!", __FILE__, __LINE__);
            continue;
        }
        else if(recv_cnt)
        {
            gettimeofday(&start, NULL);
            slog_info("[%s][%d] Data arrived! ret=[%d]", __FILE__, __LINE__, recv_cnt);
            for (i = 0; i < recv_cnt; i++)
            {
                if(fd_work[i].fd != server_sockfd )
                {
                    //-------------------------处理数据不合理需要修改----------------------------------------------------------------
                    slog_info("[%s][%d] fd=[%d]", __FILE__, __LINE__, fd_work[i].fd);
                    read(fd_work[i].fd, msg_len_buf, sizeof(msg_len_buf) - 1);
                    msg_len = strtol(msg_len_buf, NULL, 10);
                    if(msg_len > 0)
                    {
                        slog_info("recv msg_len = [%ld]", msg_len);
                        fd_work[i].data = calloc(sizeof(char), msg_len + 5);
                        if(fd_work[i].data == NULL)
                        {
                            slog_info("calloc error!");
                            continue;
                        }
                        read(fd_work[i].fd, fd_work[i].data, msg_len);
                    }
                    ret = fd_work[i].event_handler(fd_work[i].data);
                    if (ret < 0)
                    {
                        free(fd_work[i].data);
                        slog_info("[%s][%d] event_handler error!", __FILE__, __LINE__);
                    }
                    free(fd_work[i].data);
                    write(fd_work[i].fd, "hello", 5);
                    close(fd_work[i].fd);
                    select_del_event(&fd_set_s, fd_work[i].fd);
                    gettimeofday(&end, NULL);
                    rtimer = 1000000 * (end.tv_sec - start.tv_sec) + end.tv_usec - start.tv_usec;
                    slog_info("timer = %ld us\n", rtimer);
                    //-------------------------处理数据不合理需要修改----------------------------------------------------------------
                }
                else
                {
                    slog_info("new connect!");
                    ret = fd_work[i].event_handler(fd_work[i].data);
                    if (ret < 0)
                    {
                        slog_info("[%s][%d] event_handler error!", __FILE__, __LINE__);
                    }
                }
            }
        }
        else
        {
            slog_info("select timeout\n");
        }
    }

    return SW_OK;
}
